//
// Created by QU on 24-6-8.
//
#include <iostream>
#include <fstream>
#include <sstream>
#include <functional>
#include <utility>
#include <memory>
#include <vector>
#include <map>
#include <set>

#include "cpp-primer-example/16/debug_rep.h"

using std::cout, std::cin, std::endl, std::unitbuf;

// 声明
template <typename T, typename... Args>
void foo(const T& t, const Args&... rest);

// 实现
template <typename T, typename... Args>
void foo(const T& t, const Args&... rest)
{
    // 使用"sizeof..."取得个数, 注意sizeof...(包含...)是一个单词, 他是一个运算符.
    std::cout << sizeof...(rest);
}
/////////////////////////////////////////////////////////////

// 下面两个会按照函数展开一个一个的传到函数中.
template <typename T, typename ... Args>
std::ostream & myPrint(std::ostream & os, T & t, Args args &...)
{
    os << t << ",";
    return myPrint(args);
}

template <typename T>
std::ostream & myPrint(std::ostream & os, T t)
{
    return os << t << std::endl;
}
// 最后一个函数处理的时候, 这个模版函数比上面的少了可变参数, 更加特例化, 最后调用这个函数模版处理结尾, 防止无限递归.


// 同样的你可以使用折叠表达式c++17
template <typename T, typename... Args>
std::ostream& myPrint(std::ostream& os, const T& t, const Args&... args) {
    os << t;
    ((os << ", " << args), ...); // 使用折叠表达式处理剩余参数
    return os << std::endl;
}

// 折叠表达式是 C++17 引入的特性。折叠表达式允许你对可变参数模板的参数包进行展开，并应用二元运算符，简化了对多个参数的处理。
// 在 C++17 之前，你需要使用递归模板来处理可变参数包，但折叠表达式让这一过程变得更加简洁和直观。
// 以下是折叠表达式的一些示例：
//     一元左折叠：(args + ...) 展开为 ((arg1 + arg2) + arg3) + ...
//     一元右折叠：(... + args) 展开为 arg1 + (arg2 + (arg3 + ...))
//     二元左折叠：(init op ... op args) 展开为 (((init op arg1) op arg2) op arg3) op ...
//     二元右折叠：(args op ... op init) 展开为 arg1 op (arg2 op (arg3 op ... op init))

// 包展开
template <typename ...Args>
std::ostream &errorMsg(std::ostream &os, const Args &... rest)
{
    return print(os, debug_rep(rest)...);
    // 展开为: print(os, debug_rep(a1), debug_rep(a2),.......)
    // 注意: 不要写成print(os, debug_rep(rest...));
}


int main(int argc, char* argv[])
{
    int i = 0;
    double d = 3.14;
    std::string s("how now brown cow");
    foo(i, d, s, 42);
    std::hash<>
}
